package com.engine.salary.entity.salarysob.bo;

import com.engine.salary.annotation.SalaryFormulaVar;
import com.engine.salary.entity.salaryformula.ExpressFormula;
import com.engine.salary.entity.salaryformula.dto.SalaryFormulaEmployeeDTO;
import com.engine.salary.entity.salaryitem.bo.SalaryItemBO;
import com.engine.salary.entity.salaryitem.po.SalaryItemPO;
import com.engine.salary.entity.salarysob.dto.*;
import com.engine.salary.entity.salarysob.po.*;
import com.engine.salary.enums.SalaryValueTypeEnum;
import com.engine.salary.enums.salarysob.IncomeCategoryEnum;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.SalaryI18nUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import weaver.general.BaseBean;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 将薪资账套的员工信息、薪资项目副本、薪资项目分类聚合在一起
 * <p>Copyright: Copyright (c) 2022</p>
 * <p>Company: 泛微软件</p>
 *
 * @author qiantao
 * @version 1.0
 **/
@AllArgsConstructor
@NoArgsConstructor
public class SalarySobItemAggregateBO {

    /**
     * 薪资账套
     */
    private SalarySobPO salarySob;

    /**
     * 薪资账套的员工信息
     */
    private List<SalarySobEmpFieldPO> salarySobEmpFields;

    /**
     * 薪资账套的薪资项目分类
     */
    private List<SalarySobItemGroupPO> salarySobItemGroups;

    /**
     * 薪资账套的薪资项目副本
     */
    private List<SalarySobItemPO> salarySobItems;

    /**
     * 薪资账套的薪资项目副本所用公式详情
     */
    private List<ExpressFormula> expressFormulas;

    /**
     * 薪资账套的薪资项目副本所关联的薪资项目
     */
    private List<SalaryItemPO> salaryItems;

    /**
     * 薪资回算项目
     */
    private List<SalarySobBackItemPO> salarySobBackItems;

    /**
     * 账套默认项目
     */
    List<SalarySobDefaultItemPO> salarySobDefaultItemPOS;

    private final BaseBean baseBean = new BaseBean();

    //强制开启账套的公式配置
    private final Boolean openFormulaForcedEditing = "true".equals(baseBean.getPropValue("hrmSalary", "openFormulaForcedEditing"));

    /**
     * 转换成聚合dto
     *
     * @return
     */
    public SalarySobItemAggregateDTO convert2AggregateDTO() {
        List<SalarySobItemDTO> itemsWithoutGroup = Lists.newArrayList();
        // 薪资账套的薪资项目分类po转换成dto
        List<SalarySobItemGroupDTO> salarySobItemGroupDTOS = salarySobItemGroups.stream()
                .map(e -> SalarySobItemGroupDTO.builder()
                        .id(e.getId())
                        .salarySobId(e.getSalarySobId())
                        .name(e.getName())
                        .sortedIndex(e.getSortedIndex())
                        .itemHide(e.getItemHide())
                        .build())
                .collect(Collectors.toList());
        Map<Long, SalarySobItemGroupDTO> salarySobItemGroupDTOMap = SalaryEntityUtil.convert2Map(salarySobItemGroupDTOS, SalarySobItemGroupDTO::getId);

        salarySobDefaultItemPOS = salarySobDefaultItemPOS.stream().filter(po -> po.getSysSalaryItemId() != 0).collect(Collectors.toList());
        Map<Long, Integer> longIntegerMap = SalaryEntityUtil.convert2Map(salarySobDefaultItemPOS, SalarySobDefaultItemPO::getSysSalaryItemId, SalarySobDefaultItemPO::getCanDelete);
        salaryItems.forEach(item -> {
            if (item.getSystemType() == 1) {
                item.setCanDelete(1);
                if (item.getSysSalaryItemId() != null) {
                    item.setCanDelete(longIntegerMap.getOrDefault(item.getSysSalaryItemId(), 1));
                }
            }
        });

        Map<Long, SalaryItemPO> salaryItemMap = SalaryEntityUtil.convert2Map(salaryItems, SalaryItemPO::getId);
        Map<Long, List<SalarySobItemPO>> salarySobItemMap = SalaryEntityUtil.group2Map(salarySobItems, SalarySobItemPO::getSalarySobItemGroupId);
        Map<Long, String> formulaMap = SalaryEntityUtil.convert2Map(expressFormulas, ExpressFormula::getId, ExpressFormula::getFormula);


        // 薪资账套的薪资项目副本po转换成dto
        salarySobItemMap.forEach((k, v) -> {
            List<SalarySobItemDTO> items = Lists.newArrayList();
            for (int i = 0; i < v.size(); i++) {
                SalarySobItemPO salarySobItemPO = v.get(i);
                SalaryItemPO salaryItemPO = salaryItemMap.get(salarySobItemPO.getSalaryItemId());
                if (salaryItemPO != null) {
                    Integer valueType = Optional.ofNullable(salarySobItemPO.getValueType()).orElse(salaryItemPO.getValueType());
                    items.add(SalarySobItemDTO.builder()
                            .id(salarySobItemPO.getId())
                            .salarySobId(salarySob.getId())
                            .salaryItemGroupId(k)
                            .salaryItemId(salaryItemPO.getId())
                            .dataType(salaryItemPO.getDataType())
                            .valueType(valueType)
                            .roundingMode(Optional.ofNullable(salarySobItemPO.getRoundingMode()).orElse(salaryItemPO.getRoundingMode()))
                            .pattern(Optional.ofNullable(salarySobItemPO.getPattern()).orElse(salaryItemPO.getPattern()))
                            .name(salaryItemPO.getName())
                            .itemHide(salarySobItemPO.getItemHide())
                            .formulaId(salarySobItemPO.getFormulaId())
                            .formulaContent(formulaMap.getOrDefault(salarySobItemPO.getFormulaId(), ""))
                            .originFormulaContent(valueType == SalaryValueTypeEnum.FORMULA.getValue() ? formulaMap.getOrDefault(salarySobItemPO.getFormulaId(), "") : "")
                            .originSqlContent(valueType == SalaryValueTypeEnum.SQL.getValue() ? formulaMap.getOrDefault(salarySobItemPO.getFormulaId(), "") : "")
                            .taxDeclarationColumn(SalaryItemBO.buildTaxDeclarationColumn(salaryItemPO.getCode()))
                            .sortedIndex(salarySobItemPO.getSortedIndex())
                            .canEdit(openFormulaForcedEditing || Objects.equals(salaryItemPO.getCanEdit(), 1))
                            .canDelete(openFormulaForcedEditing || salaryItemPO.getCanDelete() == null || Objects.equals(salaryItemPO.getCanDelete(), 1))
                            .width(salaryItemPO.getWidth())
                            .defaultValue(salarySobItemPO.getDefaultValue())
                            .build());
                }
            }
            if (!salarySobItemGroupDTOMap.containsKey(k)) {
                itemsWithoutGroup.addAll(items);
            } else {
                SalarySobItemGroupDTO salarySobItemGroupDTO = salarySobItemGroupDTOMap.get(k);
                salarySobItemGroupDTO.setItems(sortItem(items));
            }
        });
        // 薪资账套的员工信息字段po转换成dto
        List<SalarySobEmpFieldDTO> salarySobEmpFieldDTOS = buildEmpField(salarySobEmpFields);

        List<SalarySobItemIncomeCategoryDTO> incomeCategories = Lists.newArrayList();
//        List<Integer> incomeCategoryValues = JsonUtil.parseList(salarySob.getIncomeCategory(), Integer.class);
        Integer incomeCategory = salarySob.getIncomeCategory();
        List<Integer> incomeCategoryValues = Lists.newArrayList(incomeCategory);
        for (Integer incomeCategoryValue : incomeCategoryValues) {
            IncomeCategoryEnum incomeCategoryEnum = IncomeCategoryEnum.parseByValue(incomeCategoryValue);
            SalarySobItemIncomeCategoryDTO salarySobItemIncomeCategoryDTO = new SalarySobItemIncomeCategoryDTO()
                    .setId(incomeCategoryValue.longValue())
                    .setName(Optional.ofNullable(incomeCategoryEnum)
                            .map(e -> SalaryI18nUtil.getI18nLabel(e.getLabelId(), e.getDefaultLabel()))
                            .orElse(StringUtils.EMPTY))
                    .setItemGroups(sortItemGroup(salarySobItemGroupDTOS))
                    .setItems(sortItem(itemsWithoutGroup));
            incomeCategories.add(salarySobItemIncomeCategoryDTO);
        }
        // 薪资回算项目
        List<SalarySobItemDTO> backCalcItems = salarySobBackItems.stream()
                .map(salarySobBackItem -> {
                    SalaryItemPO salaryItem = salaryItemMap.get(salarySobBackItem.getSalaryItemId());
                    return SalarySobItemDTO.builder()
                            .id(salarySobBackItem.getId())
                            .salarySobId(salarySob.getId())
                            .salaryItemId(salaryItem.getId())
                            .salaryItemGroupId(0L)
                            .dataType(salaryItem.getDataType())
                            .name(salaryItem.getName())
                            .formulaId(salarySobBackItem.getFormulaId())
                            .formulaContent(formulaMap.getOrDefault(salarySobBackItem.getFormulaId(), "输入"))
                            .taxDeclarationColumn(SalaryItemBO.buildTaxDeclarationColumn(salaryItem.getCode()))
                            .sortedIndex(0)
                            .canEdit(true)
                            .canDelete(false)
                            .build();
                }).collect(Collectors.toList());


        return SalarySobItemAggregateDTO.builder()
                .salarySobId(salarySob.getId())
                .empFields(salarySobEmpFieldDTOS)
                .items(sortItem(itemsWithoutGroup))
                .itemGroups(sortItemGroup(salarySobItemGroupDTOMap.values()))
                .incomeCategories(incomeCategories)
                .backCalcItems(backCalcItems)
                .build();
    }

    /**
     * 薪资账套的员工信息字段po转换成dto
     *
     * @param salarySobEmpFields 薪资账套的员工信息字段
     * @return
     */
    public List<SalarySobEmpFieldDTO> buildEmpField(Collection<SalarySobEmpFieldPO> salarySobEmpFields) {
        if (CollectionUtils.isEmpty(salarySobEmpFields)) {
            return Collections.emptyList();
        }
        Field[] declaredFields = SalaryFormulaEmployeeDTO.class.getDeclaredFields();
        Map<String, String> empFieldMap = Maps.newHashMapWithExpectedSize(declaredFields.length);
        for (Field declaredField : declaredFields) {
            if (!declaredField.isAnnotationPresent(SalaryFormulaVar.class)) {
                continue;
            }
            SalaryFormulaVar annotation = declaredField.getAnnotation(SalaryFormulaVar.class);
            empFieldMap.put(declaredField.getName(), SalaryI18nUtil.getI18nLabel(annotation.labelId(), annotation.defaultLabel()));
        }
        return salarySobEmpFields.stream()
                .map(e -> SalarySobEmpFieldDTO.builder()
                        .id(e.getId())
                        .salarySobId(e.getSalarySobId())
                        .fieldId(e.getFieldCode())
                        .fieldName(empFieldMap.getOrDefault(e.getFieldCode(), ""))
                        .sortedIndex(e.getSortedIndex())
                        .canDelete(Objects.equals(e.getCanDelete(), NumberUtils.INTEGER_ONE))
                        .build())
                .collect(Collectors.toList());
    }

    /**
     * 薪资账套的薪资项目按照sortedIndex排序
     *
     * @param items 待排序的薪资账套的薪资项目
     * @return
     */
    private List<SalarySobItemDTO> sortItem(Collection<SalarySobItemDTO> items) {
        if (CollectionUtils.isEmpty(items)) {
            return Collections.emptyList();
        }
        return items.stream().sorted(Comparator.comparingInt(SalarySobItemDTO::getSortedIndex)).collect(Collectors.toList());
    }

    /**
     * 薪资账套的薪资项目分类按照sortedIndex排序
     *
     * @param itemGroups 待排序的薪资账套的薪资项目分类
     * @return
     */
    private List<SalarySobItemGroupDTO> sortItemGroup(Collection<SalarySobItemGroupDTO> itemGroups) {
        if (CollectionUtils.isEmpty(itemGroups)) {
            return Collections.emptyList();
        }
        return itemGroups.stream().map(group -> {
            if (group != null && CollectionUtils.isEmpty(group.getItems())) {
                group.setItems(new ArrayList<>());
            }
            return group;
        }).sorted(Comparator.comparingInt(SalarySobItemGroupDTO::getSortedIndex)).collect(Collectors.toList());
    }
}
